﻿using System;
using CacheManager.Core;
using Microsoft.Practices.ServiceLocation;
//using StackExchange.Redis;

namespace BSF.CacheManager
{
    public class CacheMgr<T>
    {
        public static ICacheManager<T> _cache;

        public static ICacheManager<T> Cache
        {
            get
            {
                if (_cache == null)
                {
                    //ServiceLocator是反模式
                    _cache = ServiceLocator.Current.GetInstance<ICacheManager<T>>();
                    //.Net缓存管理框架CacheManager http://www.tuicool.com/articles/nmyUb2r
                    //.Net缓存管理框架CacheManager http://www.cnblogs.com/Leo_wl/p/5008680.html
                    //_cache = CacheFactory.Build<int>("myCache", settings =>
                    //{
                    //    settings
                    //    //.WithSystemRuntimeCacheHandle("inProcessCache")//内存缓存Handle
                    //    ////.WithExpiration(ExpirationMode.Sliding, TimeSpan.FromSeconds(60)))
                    //    ////.EnableStatistics()
                    //    ////.EnablePerformanceCounters()
                    //    //.And

                    //    .WithRedisConfiguration("redis", config =>//Redis缓存配置
                    //    {
                    //        config.WithAllowAdmin()
                    //         .WithDatabase(0)
                    //         .WithEndpoint("localhost", 6379);
                    //    })
                    //    //.WithExpiration(ExpirationMode.Sliding, TimeSpan.FromHours(24))
                    //    .WithMaxRetries(1000)//尝试次数
                    //    .WithRetryTimeout(100)//尝试超时时间
                    //    .WithRedisBackPlate("redis")//redis使用Back Plate,BackPlate解决分布式缓存中的同步问题
                    //    .WithRedisCacheHandle("redis", true);//redis缓存handle
                    //});
                }
                return _cache;
            }
        }
        //static CacheMgr()
        //{
        //    if (_cache == null)
        //    {
        //        _cache = ServiceLocator.Current.GetInstance<ICacheManager<T>>();
        //    }
        //}

    }

    /// <summary>
    /// 分布式缓存辅助类
    /// </summary>
    public static class CacheHelper
    {
        public static ICacheManager<T> Manager<T>()
        {
            return CacheMgr<T>.Cache;
        }

        /// <summary>
        /// 获取缓存，如果key值已存在，则直接获取；如果不存在，加载外部数据到缓存，然后返回
        /// </summary>
        /// <typeparam name="T">缓存的对象类型</typeparam>
        /// <param name="key">缓存Key</param>
        /// <param name="ifNotExistsThenGetData">如果缓存不存在时调用该委托加载数据到缓存</param>
        /// <returns></returns>
        public static T Get<T>(string key, Func<string, T> ifNotExistsThenGetData = null)
        {
            if (ifNotExistsThenGetData == null)
            {
                return CacheMgr<T>.Cache.Get(key);
            }
            return CacheMgr<T>.Cache.GetOrAdd(key, ifNotExistsThenGetData);
            //var result = CacheMgr<T>.Cache.Get(key);
            //if (result == null && ifNotExistsThenGetData != null)
            //{
            //    var data = ifNotExistsThenGetData(key);
            //    CacheMgr<T>.Cache.Add(key, data);
            //    result = data;
            //}
            //return result;
        }


        /// <summary>
        /// 获取缓存，如果key值已存在，则直接获取；如果不存在，加载外部数据到缓存，然后返回
        /// </summary>
        /// <typeparam name="T">缓存的对象类型</typeparam>
        /// <param name="key">缓存Key</param>
        /// <param name="ifNotExistsThenGetData">如果缓存不存在时调用该委托加载数据到缓存</param>
        /// <param name="expireSecond">过期时间(秒)</param>
        /// <param name="region">区域(分组)</param>
        /// <returns></returns>
        public static T GetOrAdd<T>(string key, Func<string, T> ifNotExistsThenGetData = null, int expireSecond = 0, string region = "")
        {
            var cache = CacheMgr<T>.Cache;
            var result = cache.Get(key);
            if (result == null && ifNotExistsThenGetData != null)
            {
                var data = ifNotExistsThenGetData(key);

                if (string.IsNullOrWhiteSpace(region))
                {
                    if (expireSecond > 0)
                    {
                        var item = new CacheItem<T>(key, data, ExpirationMode.Absolute, TimeSpan.FromSeconds(expireSecond));
                        cache.Add(item);
                    }
                    else
                    {
                        cache.Add(key, data);
                    }
                }
                else
                {
                    if (expireSecond > 0)
                    {
                        var item = new CacheItem<T>(key, region, data, ExpirationMode.Absolute, TimeSpan.FromSeconds(expireSecond));
                        cache.Add(item);
                    }
                    else
                    {
                        cache.Add(key, data, region);
                    }
                }

                result = data;
            }
            return result;
        }

        public static TOut Get<TOut>(string key, string region)
        {
            return CacheMgr<TOut>.Cache.Get(key, region);
        }

        public static bool Add<TCacheValue>(CacheItem<TCacheValue> item)
        {
            return CacheMgr<TCacheValue>.Cache.Add(item);
        }


        public static bool Add<TCacheValue>(string key, TCacheValue value)
        {
            return CacheMgr<TCacheValue>.Cache.Add(key, value);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="TCacheValue"></typeparam>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="region"></param>
        /// <returns></returns>
        public static bool Add<TCacheValue>(string key, TCacheValue value, string region)
        {
            return CacheMgr<TCacheValue>.Cache.Add(key, value, region);
        }


        /// <summary>
        /// 添加或更新缓存（如果key不存在，则添加，如果key已经存在则执行更新操作）
        /// </summary>
        /// <typeparam name="TCacheValue"></typeparam>
        /// <param name="key"></param>
        /// <param name="addValue"> 该值被添加，如果key不存在</param>
        /// <param name="updateValue">如果key已经存在了，则执行该委托方法获取最新的值</param>
        /// <returns></returns>
        public static TCacheValue AddOrUpdate<TCacheValue>(string key, TCacheValue addValue, Func<TCacheValue, TCacheValue> updateValue)
        {
            return CacheMgr<TCacheValue>.Cache.AddOrUpdate(key, addValue, updateValue);
        }

        public static void Clear()
        {
            CacheMgr<object>.Cache.Clear();
        }

        /// <summary>
        /// 按区域删除
        /// </summary>
        /// <param name="region">区域(分组)</param>
        public static void ClearRegion(string region)
        {
            CacheMgr<object>.Cache.ClearRegion(region);
        }


        public static CacheItem<TCacheValue> GetCacheItem<TCacheValue>(string key, string region)
        {
            return CacheMgr<TCacheValue>.Cache.GetCacheItem(key, region);
        }

        public static void Put<TCacheValue>(CacheItem<TCacheValue> item)
        {
            CacheMgr<TCacheValue>.Cache.Put(item);
        }

        public static void Put<TCacheValue>(string key, TCacheValue value)
        {
            CacheMgr<TCacheValue>.Cache.Put(key, value);
        }

        public static void Put<TCacheValue>(string key, TCacheValue value, string region)
        {
            CacheMgr<TCacheValue>.Cache.Put(key, value, region);
        }

        public static bool Remove(string key)
        {
            return CacheMgr<object>.Cache.Remove(key);
        }

        public static bool Remove(string key, string region)
        {
            return CacheMgr<object>.Cache.Remove(key, region);
        }

        public static void RemoveExpiration(string key)
        {
            CacheMgr<object>.Cache.RemoveExpiration(key);
        }

        public static void RemoveExpiration(string key, string region)
        {
            CacheMgr<object>.Cache.RemoveExpiration(key, region);
        }

        #region 模糊搜索
        //private static ConnectionMultiplexer _redis;
        //private static object _locker = new object();
        //public static ConnectionMultiplexer ManagerConnection
        //{
        //    get
        //    {
        //        if (_redis == null)
        //        {
        //            lock (_locker)
        //            {
        //                //if (_redis != null) return _redis;
        //                if (_redis == null || !_redis.IsConnected)
        //                {
        //                    string configurationOptions =
        //                        RedisManagerv4.RedisConfig.ReadServerConStr.Split(new char[] { ',' }).FirstOrDefault();
        //                    _redis = ConnectionMultiplexer.Connect(configurationOptions);
        //                    return _redis;
        //                }
        //            }
        //        }
        //        return _redis;
        //    }
        //}

        ///// <summary>
        ///// 模糊删除缓存
        ///// </summary>
        ///// <param name="key"></param>
        ///// <returns></returns>
        //public static bool RemoveLike(string key)
        //{
        //    //通过keys进行模糊查询后的批量操作
        //    //var redis = ConnectionMultiplexer.Connect("192.168.0.252:6379,allowAdmin = true");
        //    var redis = ManagerConnection;
        //    //在C#中使用lua的语法调用lua脚本
        //    redis.GetDatabase().ScriptEvaluate(LuaScript.Prepare(
        //        //Redis的keys模糊查询：
        //        " local ks = redis.call('KEYS', @keypattern) " + //local ks为定义一个局部变量，其中用于存储获取到的keys
        //        " for i=1,#ks,5000 do " +    //#ks为ks集合的个数, 语句的意思： for(int i = 1; i <= ks.Count; i+=5000)
        //        "     redis.call('del', unpack(ks, i, math.min(i+4999, #ks))) " + //Lua集合索引值从1为起始，unpack为解包，获取ks集合中的数据，每次5000，然后执行删除
        //        " end " +
        //        " return true "
        //        ),
        //        new { keypattern = key + "*" });
        //    return true;
        //}
        #endregion
    }
}
